<?php
/*
 * $Id: FileTest.class.php 127 2009-06-20 05:41:01Z namba@craid.co.jp $
 * =============================================================================
 * Barge - Web application framework on PHP5 
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * =============================================================================
 * For more information, see http://barge.googlecode.com/
 */
namespace barge\file;

use \Exception;
use \UnitTestCase;

use barge\io\File;
use barge\io\FileNotFoundException;
use barge\io\IOException;

/**
 * @see UnitTestCase
 */
class FileTest extends UnitTestCase 
{
	protected $baseDir;
	
	/**
	 * @see UnitTestCase#startUp
	 */
	public function setUp()
	{
		$this->baseDir = dirname(__FILE__).'/test';
		mkdir($this->baseDir);
	}
	
	/**
	 * @see UnitTestCase#tearDown
	 */
	public function tearDown()
	{
		$this->removeDirs($this->baseDir);
	}
	
	private function removeDirs($dir) 
	{
		$dp = dir($dir);
		if ($dp !== false) {
			while (($file = $dp->read()) !== false) {
				if ($file[0] === '.') continue;
				$path = $dir.'/'.$file;
				if (is_dir($path)) {
					$this->removeDirs($path);
					rmdir($path);
				} else {
					unlink($path);
				}
			}
			$dp->close();
//			closedir($dp);
		}
	}

	
	/**
	 * @see File#exists
	 */
	public function testExists() 
	{
		$this->assertIdentical(File::exists($this->baseDir.'/test'), false);
		mkdir($this->baseDir.'/test');
		$this->assertIdentical(File::exists($this->baseDir.'/test'), true);

		$this->assertIdentical(File::exists($this->baseDir.'/test.txt'), false);
		file_put_contents($this->baseDir.'/test.txt', 'test');
		$this->assertIdentical(File::exists($this->baseDir.'/test.txt'), true);
	}
	
	/**
	 * @see File#getContents
	 */
	public function testGetContents() 
	{
		file_put_contents($this->baseDir.'/test.txt', 'test');
		$this->assertIdentical(File::getContents($this->baseDir.'/test.txt'), 'test');
		try {
			File::getContents($this->baseDir.'/test2.txt');
			$this->fail();
		} catch (FileNotFoundException $e) {}
	}
	
	/**
	 * @see File#getContents
	 */
	public function testGetDirName() 
	{
		$this->assertIdentical(File::getDirName('c:/temp/text.txt'), 'c:/temp');
		$this->assertIdentical(File::getDirName('c:/temp/text'), 'c:/temp');
		$this->assertIdentical(File::getDirName('c:\temp/text'), 'c:\temp');
		$this->assertIdentical(File::getDirName(null), null);
	}
	
	/**
	 * @see File#getContents
	 */
	public function testGetExtName() 
	{
		$this->assertIdentical(File::getExtName('text.txt'), 'txt');
		$this->assertIdentical(File::getExtName('c:/temp/text.txt'), 'txt');
		$this->assertIdentical(File::getExtName('TEXT.JPG'), 'jpg');
		$this->assertIdentical(File::getExtName('TEXT'), null);
	}
	
	/**
	 * @see File#getContents
	 */
	public function testGetBaseName() 
	{
		$this->assertIdentical(File::getBaseName('text.txt'), 'text.txt');
		$this->assertIdentical(File::getBaseName('/text.txt'), 'text.txt');
		$this->assertIdentical(File::getBaseName('c:/temp/text.txt'), 'text.txt');
		$this->assertIdentical(File::getBaseName('c:/temp'), 'temp');
		$this->assertIdentical(File::getBaseName('c:/temp/'), 'temp');
		$this->assertIdentical(File::getBaseName(null), null);
	}
	
	/**
	 * @see File#getFileSize
	 */
	public function testGetFileSize() 
	{
		file_put_contents($this->baseDir.'/test.txt', 'test');
		$this->assertIdentical(File::getFileSize($this->baseDir.'/test.txt'), 4);
		try {
			File::getFileSize(null);
			$this->fail();
		} catch (FileNotFoundException $e) {}
		try {
			File::getFileSize($this->baseDir.'/test_none.txt');
			$this->fail();
		} catch (FileNotFoundException $e) {}
	}
	
	/**
	 * @see File#getLastModified
	 */
	public function testGetLastModified() 
	{
		$time = time();
		touch($this->baseDir.'/test.txt', $time);
		$this->assertIdentical(File::getLastModified($this->baseDir.'/test.txt')->format('U'), strval($time));
		try {
			File::getFileSize($this->baseDir.'/test_none.txt');
			$this->fail();
		} catch (FileNotFoundException $e) {}
	}
	
	/**
	 * @see File#isDir
	 */
	public function testIsDir() 
	{
		$this->assertIdentical(File::isDir($this->baseDir.'/test'), false);
		mkdir($this->baseDir.'/test');
		$this->assertIdentical(File::isDir($this->baseDir.'/test'), true);
		$this->assertIdentical(File::isDir(null), false);
	}
	
	/**
	 * @see File#isFile
	 */
	public function testIsFile() 
	{
//		fileperms()
		$this->assertIdentical(File::isFile($this->baseDir.'/test'), false);
		$this->assertIdentical(File::isFile(null), false);
		mkdir($this->baseDir.'/test');
		$this->assertIdentical(File::isFile($this->baseDir.'/test'), false);
		file_put_contents($this->baseDir.'/test/file.txt', 'test');
		$this->assertIdentical(File::isFile($this->baseDir.'/test/file.txt'), true);
	}

	/**
	 * @see File#isLink
	 */
	public function testIsLink() 
	{

	}

	/**
	 * @see File#makeDir
	 */
	public function testMakeDir() 
	{
		File::makeDir($this->baseDir.'/dir');
		$this->assertIdentical(is_dir($this->baseDir.'/dir'), true);
		
		// Dumplication.
		try {
			File::makeDir($this->baseDir.'/dir');
			$this->fail();
		} catch (FileNotFoundException $e) {}
		
		// Recursive
		try {
			File::makeDir($this->baseDir.'/dir/subdir1/subdir2');
			$this->fail();
		} catch (FileNotFoundException $e) {}
		
		File::makeDir($this->baseDir.'/dir/subdir1/subdir2', true);
		$this->assertIdentical(is_dir($this->baseDir.'/dir/subdir1/subdir2'), true);
	}
	
	/**
	 * @see File#putContents
	 */
	public function testPutContents() 
	{
		$path = $this->baseDir.'/file.txt';
		File::putContents($this->baseDir.'/file.txt', 'test1');
		File::putContents($this->baseDir.'/file.txt', 'test2');
		$this->assertIdentical(file_get_contents($path), 'test2');
		unlink($path);

		File::putContents($this->baseDir.'/file.txt', 'test1');
		File::putContents($this->baseDir.'/file.txt', 'test2', true);
		$this->assertIdentical(file_get_contents($path), 'test1test2');
		unlink($path);
		
		// Exception
		try {
			File::putContents($this->baseDir, 'test');
			$this->fail();
		} catch (FileNotFoundException $e) {}
	}
	
	/**
	 * @see File#removeDir
	 */
	public function testRemoveDir() 
	{
		// Normally case
		$path = $this->baseDir.'/dir';
		mkdir($path);
		
		File::removeDir($path);
		$this->assertIdentical(is_dir($path), false);
		
		// Directory dose not exists.
		try {
			File::removeDir($path);
			$this->fail();
		} catch (FileNotFoundException $e) {}		
		
		// Directory dose not exists.
		try {
			File::removeDir($path, true);
			$this->fail();
		} catch (FileNotFoundException $e) {}
		
		// Nested 
		mkdir($this->baseDir.'/dir');
		file_put_contents($this->baseDir.'/dir/test.txt', 'test');
		mkdir($this->baseDir.'/dir/subdir');
		file_put_contents($this->baseDir.'/dir/subdir/test.txt', 'test');
		
		try {
			File::removeDir($this->baseDir.'/dir', false);
			$this->fail();
		} catch (FileNotFoundException $e) {}

		File::removeDir($this->baseDir.'/dir', true);
		$this->assertIdentical(is_dir($this->baseDir.'/dir'), false);
	}
	
	/**
	 * @see File#removeAll
	 */
	public function testRemoveFiles() 
	{		
		// Directory dose not exists.
		try {
			File::removeFiles($path);
			$this->fail();
		} catch (FileNotFoundException $e) {}		
		
		// Directory dose not exists.
		try {
			File::removeFiles($path, true);
			$this->fail();
		} catch (FileNotFoundException $e) {}

		// Normally case
		$path = $this->baseDir.'/dir';
		mkdir($path);
		
		File::removeFiles($path);
		$this->assertIdentical(is_dir($path), true);
		
		// Nested 
		mkdir($this->baseDir.'/dir');
		file_put_contents($this->baseDir.'/dir/test.txt', 'test');
		mkdir($this->baseDir.'/dir/subdir');
		file_put_contents($this->baseDir.'/dir/subdir/test.txt', 'test');
		
		try {
			File::removeFiles($this->baseDir.'/dir', false);
			$this->fail();
		} catch (FileNotFoundException $e) {}

		File::removeFiles($this->baseDir.'/dir', true);
		$this->assertIdentical(is_dir($this->baseDir.'/dir'), true);
		$this->assertIdentical(file_exists($this->baseDir.'/dir/test.txt'), false);
		$this->assertIdentical(is_dir($this->baseDir.'/dir/subdir'), false);
	}
	
	/**
	 * @see File#unlink
	 */
	public function testUnlink() 
	{
		try {
			File::unlink($this->baseDir.'/dir', false);
			$this->fail();
		} catch (FileNotFoundException $e) {}
		mkdir($this->baseDir.'/dir');
		try {
			File::unlink($this->baseDir.'/dir', false);
			$this->fail();
		} catch (FileNotFoundException $e) {}
		file_put_contents($this->baseDir.'/file.txt', 'test');
		File::unlink($this->baseDir.'/file.txt');
		$this->assertIdentical(file_exists($this->baseDir.'/file.txt'), false);
	}
	
	/**
	 * @see File#rename
	 */
	public function testRename() 
	{
		mkdir($this->baseDir.'/dir');
		File::rename($this->baseDir.'/dir', $this->baseDir.'/dirnew');
		$this->assertIdentical(file_exists($this->baseDir.'/dir'), false);
		$this->assertIdentical(file_exists($this->baseDir.'/dirnew'), true);
		
		file_put_contents($this->baseDir.'/file.txt', 'test');
		File::rename($this->baseDir.'/file.txt', $this->baseDir.'/filenew.txt');
		$this->assertIdentical(file_exists($this->baseDir.'/file.txt'), false);
		$this->assertIdentical(file_exists($this->baseDir.'/filenew.txt'), true);
		
		// Nested directory
		mkdir($this->baseDir.'/dir2');
		file_put_contents($this->baseDir.'/dir2/file.txt', 'test');
		File::rename($this->baseDir.'/dir2', $this->baseDir.'/dirnew2');
		$this->assertIdentical(file_exists($this->baseDir.'/dirnew2'), true);
		$this->assertIdentical(file_exists($this->baseDir.'/dirnew2/file.txt'), true);
		
		// Exception.
		try {
			File::rename($this->baseDir.'/dir3', $this->baseDir.'/dir4');
			$this->fail();
		} catch (IOException $e) {}
		
		// Exception.
		try {
			File::rename($this->baseDir.'/file3.txt', $this->baseDir.'/file4.txt');
			$this->fail();
		} catch (IOException $e) {}
	}
	
	/**
	 * @see File#rename
	 */
	public function testCopyFile() 
	{
		file_put_contents($this->baseDir.'/file1.txt', 'test');
		File::copyFile($this->baseDir.'/file1.txt', $this->baseDir.'/file2.txt');
		$this->assertIdentical(file_exists($this->baseDir.'/file1.txt'), true);
		$this->assertIdentical(file_exists($this->baseDir.'/file2.txt'), true);
		
		// Exception case
		try {
			mkdir($this->baseDir.'/dir1');
			File::copyFile($this->baseDir.'/dir1', $this->baseDir.'/dir2');
			$this->fail();
		} catch (IOException $e) {}

		try {
			File::copyFile($this->baseDir.'/file3.txt', $this->baseDir.'/file4.txt');
			$this->fail();
		} catch (IOException $e) {}
		
		// Override
		file_put_contents($this->baseDir.'/file3.txt', 'test3');
		file_put_contents($this->baseDir.'/file4.txt', 'test4');
		File::copyFile($this->baseDir.'/file3.txt', $this->baseDir.'/file4.txt');
		$this->assertIdentical(file_get_contents($this->baseDir.'/file4.txt'), 'test3');
	}
	
	/**
	 * @see File#rename
	 */
	public function testCopyDir() 
	{
		mkdir($this->baseDir.'/srcdir');
		mkdir($this->baseDir.'/distdir');
		file_put_contents($this->baseDir.'/srcdir/file1.txt', 'test');
		File::copyDir($this->baseDir.'/srcdir', $this->baseDir.'/distdir');
		$this->assertIdentical(file_exists($this->baseDir.'/distdir/file1.txt'), true);
		$this->assertIdentical(file_exists($this->baseDir.'/srcdir/file1.txt'), true);
		
//		// Exception case
//		try {
//			mkdir($this->baseDir.'/dir1');
//			File::copyFile($this->baseDir.'/dir1', $this->baseDir.'/dir2');
//			$this->fail();
//		} catch (IOException $e) {}
//
//		try {
//			File::copyFile($this->baseDir.'/file3.txt', $this->baseDir.'/file4.txt');
//			$this->fail();
//		} catch (IOException $e) {}
//		
//		// Override
//		file_put_contents($this->baseDir.'/file3.txt', 'test3');
//		file_put_contents($this->baseDir.'/file4.txt', 'test4');
//		File::copyFile($this->baseDir.'/file3.txt', $this->baseDir.'/file4.txt');
//		$this->assertIdentical(file_get_contents($this->baseDir.'/file4.txt'), 'test3');
	}
	
	/**
	 * @see File#concatPath
	 */
	public function testConcatPath() 
	{
		$this->assertIdentical(File::concatPath('c:\temp', 'file.txt'), 'c:\temp/file.txt');
		$this->assertIdentical(File::concatPath('/var/www/', 'html'), '/var/www/html');
		$this->assertIdentical(File::concatPath('/var/www', 'html', 'index.html'), '/var/www/html/index.html');
	}
	
	/**
	 * @see File#getInputStream
	 */
	public function testGetInputStream() 
	{
		try {
			$is = File::getInputStream($this->baseDir.'/file.txt');
			$this->fail();
		} catch (FileNotFoundException $e) {}
		file_put_contents($this->baseDir.'/file.txt', 'test');
		$is = File::getInputStream($this->baseDir.'/file.txt');
		$this->assertIsA($is, 'barge\io\FileInputStream');
		$is->close();
	}
	
	/**
	 * @see File#getOutoutStream
	 */
	public function testGetOutoutStream() 
	{
		// Unwritable directory
		try {
			$os = File::getOutoutStream('/temp_dir/file.txt');
			$this->fail();
		} catch (FileNotFoundException $e) {}
		$os = File::getOutoutStream($this->baseDir.'/file.txt');
		$this->assertIsA($os, 'barge\io\FileOutputStream');
		$os->close();
	}
}
